%{
#include <stdio.h>
#include <string.h>

extern int yylineno;
extern char* yytext[];
extern FILE* outFile_p;
extern int yylex();


void yyerror(const char *str)
{
  fprintf(stderr,"Erro: %s\n",str);
}

%}

%token <palavra> LABEL <palavra> INTEGER <palavra> BOOLEAN <palavra> ARRAY <palavra> REAL <palavra> DECLARE <palavra> TOKENBEGIN <palavra> END<palavra> OFF <palavra> PROCEDURE <palavra>   IF <palavra> THEN  <palavra> ELSE <palavra> DO  
%token <palavra>  WHILE <palavra> READ <palavra> WRITE <palavra> GOTO <palavra> RETURN <palavra> NOT <palavra> TOKENFALSE <palavra> TOKENTRUE <palavra> OR <palavra> AND <palavra> MINUS <palavra> EQUALS <palavra> GREATER <palavra> GREATERREQ<palavra> DIFF <palavra> SUM <palavra> TIMES <palavra> DIV <palavra> MOD <palavra> ATTRIB <palavra> SIMPLEASPAS <palavra> COLON <palavra> DOUBLEDOTS
%token <palavra> SEMICOLON <palavra> OPENPAR <palavra> CLOSEPAR <palavra> OPENSQUARE <palavra> CLOSESQUARE <palavra> LETTER <palavra> IDENTIFIER <num> DIGIT <num> INTEGERINT <palavra> CHARACTER <palavra> PROGRAM <palavra> CHAR <palavra> GREATEREQ <palavra> GRATER  <palavra> OF

%union {
	char *palavra;
	double num;
}

%start programa
%%

programa:	
	      /*empty*/ {
				printf("\tPrograma vazio\n\n");
			}
			| PROGRAM identifier blockstmt {
				printf("\tPROGRAM --> program identifier BLOCK-SMTM \n\n");
			}
			;
blockstmt:
		DECLARE dec1list TOKENBEGIN stmtlist END
			{
			printf("\tBLOCK-SMTM -->  declare DEC1-LIST  begin STMT-LIST end\n\n");
			}
			| TOKENBEGIN stmtlist END {
			printf("\tBLOCK-SMTM -->  begin STMT-LIST end\n\n");

			}
			;
dec1list:
		dec1 
			{
				printf("\tDEC1-LIST --> DEC1\n\n");
			}
			| dec1list SEMICOLON dec1{
				printf("\tDEC1-LIST --> DEC1-LIST ; DEC1\n\n");
			}
			;
dec1:	
		variabledec1
			{
				printf("\t DEC1 --> VARIABLE-DEC1\n\n");	
			} 
			| procdec1 {
				printf("\t DEC1 --> PROCDEC1\n\n");	
			}
			| procsignature {
				printf("\t DEC1 --> PROCDECSIGNATURE\n\n");	

			}
			;
variabledec1:
		type identlist
			{	
				printf("\t VARIABLE-DEC1 --> TYPE IDENT-LIST\n\n");
			}
			;
identlist:
		identifier 
			{
				printf("\t IDENT-LIST --> IDENTIFIER\n\n");
			}
			| identlist COLON identifier{
				printf("\t IDENT-LIST --> IDENT-LIST , IDENTIFIER\n\n");
			}	
			;
type:
		simpletype
			{
				printf("\t TYPE --> SIMPLE-TYPE\n\n");
			}
			| arraytype {
				printf("\t TYPE --> ARRAY-TYPE\n\n");
	  		  }
			;
simpletype:
		INTEGER
			{
				printf("\t SIMPLE-TYPE --> integer\n\n");
			}
			| BOOLEAN {
				printf("\t SIMPLE-TYPE --> boolean\n\n");
			}
			| CHAR {
				
				printf("\t SIMPLE-TYPE --> char\n\n");
			}
			| LABEL {
				printf("\t SIMPLE-TYPE --> LABEL\n\n");
			}
			| REAL {
				printf("\t SIMPLE-TYPE --> real\n\n");
			}
			;
arraytype:
		ARRAY tamanho OF simpletype
			{
				printf("\t ARRAY-TYPE --> array TAMANHO of SIMPLE-TYPE\n\n");
			}
			;
tamanho:
		integerconstant
			{
				printf("\t TAMANHO -->  INTEGER-CONSTANT \n\n");
			}
			;
procdec1:			
		PROCEDURE identifier blockstmt
			{
				printf("\t PROC-DEC1 -->  procedure IDENTIFIER BLOCK-STMT\n\n");
			}
			| PROCEDURE identifier OPENPAR formallist CLOSEPAR blockstmt{
				printf("\t PROC-DEC1 -->  procedure IDENTIFIER ( FORMAL-LIST )  BLOCK-STMT\n\n");

			}
			;
formallist:
		parameterdec1 
			{
				
				printf("\t FORMAL-LIST -->  PARAMETER-DEC1\n\n");
			}
			| formallist SEMICOLON  parameterdec1{
				printf("\t FORMAL-LIST --> FORMAL-LIST , PARAMETER-DEC1\n\n");
			}
			;
parameterdec1:
		parametertype identifier 
			{
				printf("\t PARAMETER-DEC1 --> PARAMETER-TYPE , IDENTIFIER\n\n");
			}
			;
parametertype:
		type
			{
				printf("\t PARAMETER-TYPE --> TYPE\n\n");
			}
			;
procsignature:
		PROCEDURE identifier 
			{
				printf("\t PROC-SIGNATURE --> procedure IDENTIFIER\n\n");
			}
			| PROCEDURE identifier OPENPAR typelist CLOSEPAR {
				printf("\t PROC-SIGNATURE --> procedure IDENTIFIER ( TYPE-LIST ) \n\n");
			}
			;
typelist:
		parametertype {
				printf("\t TYPE-LIST --> PARAMETER-TYPE\n\n");
			}
			| typelist COLON parametertype {
				printf("\t TYPE-LIST --> TYPE-LIST , PARAMETER-TYPE\n\n");
			}
			;
stmtlist:
		stmt 
			{
				printf("\t STMT-LIST --> STMT\n\n");
			}
			| stmtlist SEMICOLON stmt {
				
				printf("\t STMT-LIST --> STMT-LIST ; STMT\n\n");
			}
			;
stmt:
		label DOUBLEDOTS unlabelledstmt
			{
				printf("\t STMT --> LABEL : UNLABELLEDSTMT \n\n");
			}
			| unlabelledstmt {
				printf("\t STMT --> UNLABELLEDSTMT \n\n");
			}
			;
label:
		identifier
			{
				printf("\t LABEL --> IDENTFIER\n\n");
			}
			;
unlabelledstmt:
		assignstmt
			{
				printf("\t UNLABELLED-STMT--> ASSIGNSTMT\n\n");
			}
			| ifstmt {
				printf("\t UNLABELLED-STMT--> IF-STMT\n\n");
			}
			| whilestmt {
				printf("\t UNLABELLED-STMT--> WHILE-STMT\n\n");
			}
			| readstmt {
				printf("\t UNLABELLED-STMT--> READ-STMT\n\n");
			}
			| writestmt {
				printf("\t UNLABELLED-STMT--> WRITE-STMT\n\n");
			}
			| gotostmt {
				printf("\t UNLABELLED-STMT--> GOTO-STMT\n\n");
			}
			| procstmt {
				printf("\t UNLABELLED-STMT--> PROC-STMT\n\n");
			}
			| returnstmt {
				printf("\t UNLABELLED-STMT--> RETURN-STMT\n\n");
			}
			| blockstmt {
				printf("\t UNLABELLED-STMT--> BLOCK-STMT\n\n");
			}
			;
assignstmt:
		variable ATTRIB expression
			{
				printf("\t ASSIGN-STMT--> VARIABLE := EXPRESSION\n\n");
			}
			;
variable:
		identifier
			{
				printf("\t VARIABLE --> IDENTIFIER\n\n");
			}
			| arrayelement {
				printf("\t VARIABLE --> ARRAY-ELEMENT\n\n");
			}
			;
arrayelement:
		identifier OPENSQUARE expression CLOSESQUARE 
			{
				printf("\t ARRAY-ELEMENT --> IDENTIFIER [ EXPRESSION ]\n\n");
			}
			;
ifstmt:
		IF condition THEN stmtlist END 
			{
				printf("\t IF-STMT--> if CONDITION then STMT-LIST end \n\n");
			}
			| IF condition THEN stmtlist ELSE stmtlist END {
				printf("\t IF-STMT--> if CONDITION then STMT-LIST else STMT-LIST end \n\n");
			}
			;
condition:
		expression 
			{
				printf("\t CONDITION --> EXPRESSION\n\n");
			}
			;
whilestmt:
		stmtprefix stmtlist END
			{
				printf("\t WHILE-STMT --> STMT-PREFIX STMT-LIST end\n\n");
				
			}
			;
stmtprefix:
		WHILE condition DO 
			{
				printf("\t STMT-PREFIX  --> while CONDITION do\n\n");
			}
			;
readstmt:
		READ OPENPAR identlist CLOSEPAR 
			{
				printf("\t READ-STMT --> read ( IDENT-LIST )\n\n");
			}
			;
writestmt:
		WRITE OPENPAR exprlist CLOSEPAR
			{
				printf("\t WRITE-STMT --> write ( EXPR-LIST )\n\n");
			}
			;
gotostmt:
		GOTO label
			{
				printf("\t GOTO-STMT --> goto LABEL \n\n");
			}
			;
procstmt:
		identifier 
			{
				printf("\t PROC-STMT --> IDENTIFER \n\n");
			}
			| identifier OPENPAR exprlist CLOSEPAR {
				printf("\t PROC-STMT --> IDENTIFER ( EXPR-LIST ) \n\n");
			}
			;
returnstmt:
		RETURN
			{
				printf("\t RETURN-STMT --> return\n\n");
			}
			;
exprlist:
		expression 
			{
				printf("\t EXPR-LIST --> EXPRESSION\n\n");
			}
			| exprlist COLON expression {
				printf("\t EXPR-LIST --> EXPR-LIST , EXPRESSION\n\n");
			}
			;
expression:
		simpleexpr 
			{
				printf("\t EXPRESSION --> SIMPLE-EXPR\n\n");
			}
			| simpleexpr relop simpleexpr {
				printf("\t EXPRESSION --> SIMPLE-EXPR RELOP SIMPLE-EXPR\n\n");
			}
			;
simpleexpr:
		term 
			{	
				printf("\t SIMPLE-EXPR --> TERM \n\n");
			}
			| simpleexpr addop  term {
				printf("\t SIMPLE-EXPR --> SIMPLE-EXPR ADDOP TERM \n\n");
			}
			;
term:
		factora 
			{
				printf("\t TERM --> FACTOR-A\n\n");
			}
			| term mulop factora {
				printf("\t TERM --> TERM MULOP FACTOR-A\n\n");
			}
			;
factora:
		factor 
			{
				printf("\t FACTOR-A --> FACTOR \n\n");
			}
			| NOT factor {
				printf("\t FACTOR-A --> not FACTOR \n\n");
			}
			| MINUS factor{
				printf("\t FACTOR-A --> - FACTOR \n\n");
			}
			;
factor:
		variable 
			{
				printf("\t FACTOR --> VARIABLE\n\n");
			}
			| constant {
				printf("\t FACTOR --> CONSTANT\n\n");
			}
			| OPENPAR expression CLOSEPAR {
				printf("\t FACTOR --> ( EXPRESSION )\n\n");
			}
			;
relop:
		EQUALS 
			{
				printf("\t RELOP --> =\n\n");
			}
			| GREATER {
				printf("\t RELOP --> >\n\n");
			}
			| GREATEREQ {
				printf("\t RELOP --> >=\n\n");
			}
			| DIFF {
				printf("\t RELOP --> !=\n\n");
			}
			;
addop:
		SUM 
			{
				printf("\t ADDOP --> +\n\n");
			}
			| MINUS {
				printf("\t ADDOP --> -\n\n");
			}
			| OR {
				printf("\t ADDOP --> or\n\n");
			}
			;
mulop:
		TIMES 
			{
				printf("\t MULOP --> *\n\n");
			}
			|  DIV {
				printf("\t MULOP --> /\n\n");
			}
			| AND {
				printf("\t MULOP --> and\n\n");
			}
			| MOD {
				printf("\t MULOP --> mod\n\n");
			}
			;
constant:
		integerconstant
			{
				printf("\t CONSTANT --> INTEGER-CONSTANT\n\n");
			}
			| charconstant {
				printf("\t CONSTANT --> CHAR-CONSTANT\n\n");
			}
			| booleanconstant {
				printf("\t CONSTANT --> BOOLEAN-CONSTANT\n\n");
			}
			;
booleanconstant:
	 	TOKENFALSE
			{
				printf("\t BOOLEAN-CONSTANT --> false\n\n");
			}
			| TOKENTRUE {
				printf("\t BOOLEAN-CONSTANT --> true\n\n");
			}
			;
integerconstant:
		unsignedinteger
			{
				printf("\t INTEGER-CONSTANT --> UNSIGNED-INTEGER\n\n");
			}
			;
unsignedinteger:
		DIGIT {
				printf("\t UNSIGNED-INTEGER --> DIGIT\n\n");
			}
			| unsignedinteger DIGIT {
				printf("\t UNSIGNED-INTEGER --> UNSIGED-INTEGER DIGIT\n\n");
			}
			;
charconstant:
		SIMPLEASPAS caractere SIMPLEASPAS 
			{
				printf("\t CHAR-CONSTANT --> ' CARACTER '\n\n");
			}
			;
identifier:
		IDENTIFIER 
			{
				char *pal = $1 ; 
				printf("\t IDENTIFIER --> %s \n\n",pal);
			}
			;
					

caractere:
		CHARACTER
			{
				printf("\t CARACTERE --> charactere\n\n");
			}
			;
